/*
 * 爱组搭，低代码组件化开发平台
 * ------------------------------------------
 * 受知识产权保护，请勿删除版权申明，开发平台不允许做非法网站，后果自负
 */
package com.aizuda.boot.modules.auth.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.aizuda.boot.modules.auth.domain.dto.FeiShuUserInfo;
import com.aizuda.boot.modules.auth.domain.dto.LoginParam;
import com.aizuda.boot.modules.auth.domain.entity.ThirdUser;
import com.aizuda.boot.modules.auth.domain.entity.ThirdUserAuth;
import com.aizuda.boot.modules.auth.service.IAuthService;
import com.aizuda.boot.modules.auth.service.ThirdUserAuthService;
import com.aizuda.boot.modules.auth.service.ThirdUserService;
import com.aizuda.boot.modules.business.contract.util.AuthUtil;
import com.aizuda.boot.modules.common.constant.CommonConstant;
import com.aizuda.boot.modules.common.constant.RedisKeyConstant;
import com.aizuda.boot.modules.common.constant.enums.ResponseCodeEnum;
import com.aizuda.boot.modules.common.util.RedisService;
import com.aizuda.boot.modules.system.entity.SysDepartment;
import com.aizuda.boot.modules.system.entity.SysUser;
import com.aizuda.boot.modules.system.entity.SysUserDepartment;
import com.aizuda.boot.modules.system.entity.vo.TenantVo;
import com.aizuda.boot.modules.system.mapper.SysDepartmentMapper;
import com.aizuda.boot.modules.system.service.ISysDepartmentService;
import com.aizuda.boot.modules.system.service.ISysUserDepartmentService;
import com.aizuda.boot.modules.system.service.ISysUserService;
import com.aizuda.core.api.ApiAssert;
import com.aizuda.service.spring.SpringHelper;
import com.baomidou.kisso.common.encrypt.MD5Salt;
import com.baomidou.kisso.enums.TokenOrigin;
import com.baomidou.kisso.security.token.SSOToken;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.config.AuthDefaultSource;
import me.zhyd.oauth.model.AuthUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 授权 服务实现类
 *
 * @author 青苗
 * @since 2021-12-27
 */
@Service
@AllArgsConstructor
@Slf4j
public class AuthServiceImpl implements IAuthService {

    private final SysDepartmentMapper sysDepartmentMapper;
    private final RedisService redisService;
    private ISysUserService sysUserService;

    private ThirdUserService thirdUserService;

    private ThirdUserAuthService thirdUserAuthService;

    private ISysDepartmentService sysDepartmentService;

    private ISysUserDepartmentService sysUserDepartmentService;

    @Override
    public Map<String, Object> login(HttpServletRequest request, HttpServletResponse response, LoginParam loginParam) {
        ApiAssert.fail(StringUtils.isEmpty(loginParam.getUsername())
                || StringUtils.isEmpty(loginParam.getPassword()), "用户名密码不能为空");
        List<SysUser> userList = sysUserService.list(Wrappers.<SysUser>query().eq("username", loginParam.getUsername()));
        ApiAssert.fail(null == userList || userList.size() != 1, "用户不存或异常数据");
        SysUser user = userList.get(0);
        ApiAssert.fail(Objects.equals(0, user.getStatus()), "用户已禁用，请联系管理员");
        ApiAssert.fail(!MD5Salt.isValid(user.getUsername() + user.getSalt()
                , user.getPassword(), loginParam.getPassword()), "登录密码错误");

        // 登录信息
        return loginInfo(request, user);
    }

    /**
     * 设置登录信息
     */
    private Map<String, Object> loginInfo(HttpServletRequest request, SysUser user) {
        // 登录时清除用户缓存，确保获取最新的用户信息
        String cacheKey = RedisKeyConstant.LOGIN_USER_PREFIX + user.getId();
        redisService.deleteObject(cacheKey);
        log.info("登录时清除用户缓存: {}", cacheKey);
        
        Map<String, Object> loginInfo = new HashMap<>(4);
        loginInfo.put("token", new SSOToken()
                .id(user.getId())
                .issuer(user.getUsername())
                .tenantId(user.getSysTenantVo().getTenantKey())
                .userAgent(request)
                .origin(TokenOrigin.HTML5)
                .data(new HashMap<>() {{
                          // 设置会话ID，用于区分客户端消息发送
                          put("sid", IdWorker.get32UUID());
                          put("userId", user.getId());
                          put("userName", user.getNickName());
                          put("sysTenant", user.getSysTenantVo());
                          put(AuthUtil.FEISHU_TENANT_KEY, user.getFeiShuTenantKey());
                      }}
                ).getToken());
        loginInfo.put("userInfo", new HashMap<String, Object>(3) {{
            put("userId", user.getId());
            put("userName", user.getNickName());
            put("sysTenant", user.getSysTenantVo());
            put(AuthUtil.FEISHU_TENANT_KEY, user.getFeiShuTenantKey());
        }});
        return loginInfo;
    }

    @Override
    public Map<String, Object> tokenLogin(HttpServletRequest request, HttpServletResponse response, LoginParam loginParam) {
        //ApiAssert.fail(StringUtils.isBlank(loginParam.getToken()), "授权票据不能为空");
        //
        //try {
        //    // 校验票据合法性，Token 为 Base64 URL 加密
        //    byte[] bytes = Base64.getUrlDecoder().decode(loginParam.getToken());
        //    String text = new String(AES.decrypt(bytes, "AIjOCLBy8D0BlSdC".getBytes(StandardCharsets.UTF_8)));
        //    long timestamp = Long.parseLong(text.substring(0, 10));
        //    long currentTime = System.currentTimeMillis() / 1000;
        //    if ((currentTime - timestamp) > 600) {
        //        ApiAssert.fail("授权票据已失效");
        //    }
        //} catch (Throwable t) {
        //    ApiAssert.fail("授权票据验证失败");
        //}

        // 固定进入 admin 账号
        SysUser user = new SysUser();
        user.setId(0L);
        user.setUsername("admin");
        user.setNickName("admin");
        return loginInfo(request, user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> feiShuLogin(AuthUser authUser, HttpServletRequest request, HttpServletResponse response) {

        AtomicReference<Map<String, Object>> loginInfo = new AtomicReference<>();
        FeiShuUserInfo feiShuUserInfo = JSONUtil.toBean(JSONUtil.toJsonStr(authUser.getRawUserInfo().getJSONObject("data")), FeiShuUserInfo.class);
        log.info("飞书用户信息: {}", JSONUtil.toJsonStr(feiShuUserInfo));
        // 根据飞书用户信息查询或创建用户
        // 如果用户存在,获取用户信息
        thirdUserService.lambdaQuery()
                .eq(ThirdUser::getSource, AuthDefaultSource.FEISHU.getName())
                .eq(ThirdUser::getUuid, feiShuUserInfo.getUnionId())
                .oneOpt()
                .ifPresentOrElse(thirdUser -> {
                    log.info("飞书用户信息已存在,获取用户信息: {}", thirdUser);
                    // 如果用户存在,获取用户信息
                    thirdUserAuthService.lambdaQuery()
                            .eq(ThirdUserAuth::getThirdUserId, thirdUser.getId())
                            .oneOpt()
                            .ifPresentOrElse(thirdUserAuth -> {
                                //    获取用户信息
                                SysUser user = sysUserService.getById(thirdUserAuth.getUserId());
                                ApiAssert.fail(null == user, "用户不存在，请重新登录");
                                ApiAssert.fail(Objects.equals(0, user.getStatus()), "用户已禁用，请联系管理员");
                                // 返回登录信息
                                //获取用户系统租户部门信息
                                SysDepartment department = sysDepartmentService.getDepByUserIdAndTenantKey(thirdUserAuth.getUserId(), thirdUser.getTenantKey());
                                SysDepartment sysTenantDept = sysDepartmentService.getSysTenantDept(thirdUserAuth.getUserId(), department.getId());
                                //设置系统租户标识
                                user.setFeiShuTenantKey(feiShuUserInfo.getTenantKey());
                                user.setSysTenantVo(TenantVo.builder()
                                        .tenantKey(sysTenantDept.getSysTenantKey())
                                        .tenantName(sysTenantDept.getName())
                                        .build());
                                loginInfo.set(loginInfo(request, user));

                            }, () -> {
                                ApiAssert.fail("第三方授权信息不存在,请重新登录");
                            });
                }, () -> {
                    //如果不存在则直接提示尚未取得系统登录权限
                    ApiAssert.fail("当前用户尚未同步到系统,请联系管理员同步飞书用户到系统");


                    //如果用户不存在,创建新用户
                    //SysUser sysUser = new SysUser();
                    //sysUser.setUsername(PinyinUtil.getPinyin(feiShuUserInfo.getName(), "") + RandomUtil.randomNumbers(4));
                    //sysUser.setNickName(feiShuUserInfo.getName());
                    //sysUser.setAvatar(feiShuUserInfo.getAvatarUrl());
                    //sysUser.setRealName(feiShuUserInfo.getName());
                    //sysUser.setEmail(feiShuUserInfo.getEmail());
                    //sysUser.setPhone(feiShuUserInfo.getMobile());
                    //sysUser.setStatus(1);
                    //sysUserService.save(sysUser);
                    //
                    //// 保存第三方用户信息
                    //ThirdUser thirdUser = new ThirdUser();
                    //thirdUser.setUuid(feiShuUserInfo.getUnionId());
                    //thirdUser.setSource(AuthDefaultSource.FEISHU.getName());
                    //thirdUser.setOpenId(feiShuUserInfo.getOpenId());
                    //thirdUser.setTenantKey(feiShuUserInfo.getTenantKey());
                    //thirdUser.setUserId(feiShuUserInfo.getUserId());
                    //thirdUserService.save(thirdUser);
                    //
                    //// 保存第三方授权信息
                    //thirdUserAuthService.save(ThirdUserAuth.builder()
                    //        .thirdUserId(thirdUser.getId())
                    //        .userId(sysUser.getId())
                    //        .userId(sysUser.getId())
                    //        .build());
                    //sysUser.setTenantKey(thirdUser.getTenantKey());
                    //loginInfo.set(loginInfo(request, sysUser));
                });


        return loginInfo.get();
    }

    @Override
    public Map<String, Object> changeSysTenant(String targetSysTenantId) {
        if (CommonConstant.ALL_TENANT_KEY.equals(targetSysTenantId)) {
            SysUser sysUser = sysUserService.getById(null);
            return loginInfo(SpringHelper.getCurrentRequest(), sysUser);
        }

        //根据目标租户id获取租户部门信息
        SysDepartment sysDepartment = sysDepartmentService.lambdaQuery()
                .eq(SysDepartment::getSysTenantKey, targetSysTenantId)
                .and(x -> x.eq(SysDepartment::getPid, 0).or().eq(SysDepartment::getIndependentFlag, 1))
                .orderByDesc(SysDepartment::getIndependentFlag)
                .last("limit 1")
                .one();
        if (ObjectUtil.isEmpty(sysDepartment)) {
            log.info("目标系统租户不存在");
            ApiAssert.fail(ResponseCodeEnum.PARAMETER_ERROR);
        }

        //当前部门下子部门id列表
        List<Long> depIds = sysDepartmentMapper.selectIdsRecursive(sysDepartment.getId());
        SysUser sysUser = sysUserService.getById(null);
        Long count = sysUserDepartmentService.lambdaQuery()
                .in(SysUserDepartment::getDepartmentId, depIds)
                .eq(SysUserDepartment::getUserId, sysUser.getId())
                .count();
        if (1 > count) {
            log.info("当前用户:{}非目标租户:{}下用户", sysUser.getId(), targetSysTenantId);
            ApiAssert.fail(ResponseCodeEnum.PARAMETER_ERROR);
        }

        // 切换租户前先清除用户缓存
        boolean cacheCleared = sysUserService.clearUserCache(sysUser.getId());
        log.info("切换系统租户时清除用户缓存，用户ID: {}, 清除结果: {}", sysUser.getId(), cacheCleared);

        sysUser.setSysTenantVo(TenantVo.builder()
                .tenantKey(sysDepartment.getSysTenantKey())
                .tenantName(sysDepartment.getName())
                .build());
        return loginInfo(SpringHelper.getCurrentRequest(), sysUser);

    }

}
